/**
 * sso-util
 * @authors 杨兴洲（of2502）
 * @date    2017/5/22 0022 14:30
 * @version 1.0
 */
import * as crypto from "crypto";
import * as util from "util";
import * as http from "http";
import {decodeCipher} from "./aes-util"
import logger from"./logger";
import CONFIG from "../config";


// SSO服务器地址
const SSO_SERVER = CONFIG.SSO_SERVER;
// 主站点票据
const ssoTicketKey = "SSOTICKET";

// 子站点票据
const siteTicketKey = "SSOCHILDTICKET";
export default async function (req): Promise<{ userId: string; userNickName: string; }> {

    // 总票据
    const ssoTicket = decode(req, ssoTicketKey) || "";
    // 子票据
    const siteTicket = decode(req, siteTicketKey);
    // 当前请求域名
    const serverUrl = util.format('%s://%s', req.protocol, req.hostname);
    logger.debug("当前请求域名:", serverUrl, '总票据:', ssoTicket, "子票据::", siteTicket);

    // 验证票据
    if (ssoTicket) {
        await refreshSiteTicket({ssoTicket});
        if (siteTicket) {
            return await getUserId(siteTicket);
        } else {
            let siteTicket = await getSiteTicket({serverUrl, ssoTicket});
            return await getUserId(siteTicket);
        }
    } else {
        throw new Error('单点登录失效, req cookie中未携带ssoTicket');
    }
}


function getUserId(siteTicket): Promise<{ userId: string; userNickName: string; }> {

    return new Promise((resolve, reject) => {
        let validateUrl = util.format('%s/api/validate?t=%s', SSO_SERVER, siteTicket);
        logger.debug('sso验证URL::', validateUrl);
        http.get(validateUrl, (res) => {
            res.on('data', (_data) => {
                try {
                    let data = JSON.parse((_data as Buffer).toString('utf-8'));
                    logger.info('从sso获取用户信息为:', data);
                    resolve({
                        userId: (data.attributeMap && data.attributeMap.parentId) || data.id,
                        userNickName: data.attributeMap && data.attributeMap.ATTR_USER_NICKNAME || ''
                    });// 如果有是子帐号, SSO会带过来父帐号parentId
                } catch (err) {
                    logger.error('sso获取子票据失败!:', err.stack);
                    reject(err);
                }
            })
        }).on('error', function (e) {
            logger.warn('sso验证失败:', e);
            reject(e);
        }).end();
    })
}


/**
 * 获取子票据&用户信息
 * @returns {Promise<T>}
 */
function getSiteTicket({ssoTicket, serverUrl}): Promise<string> {

    return new Promise((resolve, reject) => {
        let siteTicket = util.format('%s/api/alloc/siteticket?t=%s&domain=%s', SSO_SERVER, ssoTicket, serverUrl);
        logger.debug('sso获取子票据URL::', siteTicket);
        http.get(siteTicket, (res) => {
            res.on('data', function (_data) {
                try {
                    let data = JSON.parse((_data as Buffer).toString('utf-8'));
                    if (data.error && !data.siteTicket) {
                        reject(data.error);
                    } else {
                        resolve(data.siteTicket);
                    }
                } catch (err) {
                    logger.error('sso获取子票据失败!:', err.stack);
                    reject(err);
                }
            })
        }).on('error', function (e) {
            logger.warn('sso获取子票据失败!:', e);
            reject(e);
        }).end();
    })

}


/**
 * 刷新站点ticket
 * @param ssoTicket
 * @returns {Promise<T>}
 */
function refreshSiteTicket({ssoTicket}): Promise<null> {
    return new Promise((resolve, reject) => {
        let siteTicket = util.format('%s/api/refresh?t=%s', SSO_SERVER, ssoTicket);
        logger.debug('刷新站点ticket::', siteTicket);
        http.get(siteTicket, (res) => {
            res.on('data', function (_data) {
                try {
                    logger.warn('sso刷新票据返回值!:', (_data as Buffer).toString('utf-8'));
                    resolve();
                } catch (err) {
                    logger.error('sso刷新票据返回值失败!:', err.stack);
                    reject(err);
                }
            })
        }).on('error', function (e) {
            logger.warn('sso获取子票据失败!:', e);
            reject(e);
        }).end();

    });
}


/**
 * token解密 , 从客户端cookie中获取内容,并解密验证数据. ;
 *
 * @param req
 * @param name
 * @returns {any}
 */
function decode(req, name) {
    let random = req.cookies['__sso_key'] || '';
    let value = req.cookies[name] ? req.cookies[name].replace(/-/g, '+').replace(/_/g, '/').replace(/\./g, '=') : '';

    logger.debug("token解密::req.cookies[", name, "] = ", req.cookies[name]);

    if (value) {
        value = decodeCipher(value);
        logger.debug("token解密::value ", value);

        let vs = value.split('QIUFANGGUO');

        let ip = '120.55.198.118:80',
            forwardedIp = req.headers["x-forwarded-for"],
            userAgent = req.headers["user-agent"];

        let oldValid = crypto.createHash('md5').update(ip + forwardedIp + userAgent).digest('hex');
        let newValid = crypto.createHash('md5').update(random + userAgent).digest('hex');
        let newValid2 = crypto.createHash('md5').update(random).digest('hex'); //MD5Util.md5Hex(random);
        if (vs.length > 1 && vs[1] == oldValid) { //老版本 ip + userAgent
            logger.debug("老版本 ip + userAgent ", oldValid);
            return vs[0];
        } else if (vs.length > 2 && vs[2] == newValid) { //新版本 random + userAgent
            logger.debug("新版本 random + userAgent ", newValid);
            return vs[0];
        } else if (vs.length > 3 && vs[3] == newValid2) {
            logger.debug("random ", newValid2);
            return vs[0];
        }
    }
    return null;
}
